import CodeView from '../../../shared/components/CodeView';
import CodeBlock from '../../../shared/components/CodeBlock';
import Example from '../../../shared/components/Example';
import Blockquote from '../../../shared/components/Blockquote';
import { MultiSelect, MultiSelectViewMode, DefaultSnapShot, LockedSnapShot, DisabledSnapShot, SelectedSnapShot, MultiSelectedSnapShot, GrabbedSnapShot, MovedInSnapShot, DroppedSnapShot, MoveToSnapShot, CountriesSnapshot, SelectedCountriesSnapshot, MultipleSelectedCountriesSnapshot, DroppedCountriesSnapshot, Demo } from './';
import { DoctypeIcon } from '../icons/doctype/example';

<div className="doc lead">
  A dueling-picklist is used to move options between two lists and is often
  referred to as a multi-select. Sometimes, the list options can then be
  re-ordered, depending on the use case.
</div>

<CodeView exampleOnly>
  <MultiSelect dataSet={SelectedCountriesSnapshot} noReorder />
</CodeView>

## About Dueling-Picklist

### Accessibility

This component is essentially 2 ARIA listboxes side by side, so we follow the [ARIA practices guide](https://www.w3.org/TR/wai-aria-practices/#Listbox) to help implement their interaction in an accessible way. Some additional details, supplementary to the ARIA guide include:

#### Markup

- `aria-multiselectable="true"` should be set on each listbox
- `aria-selected` should be placed on each `role="option"`, and set to `false` by default
- `aria-labelledby` is used to identify the list to the user and should point to the list label
- `aria-describedby` is used to provide operation instructions for the Drag and Drop interaction
- `tabindex` should be set to "0" when an item is selected and "-1" otherwise

#### Focus Management

- Initially, nothing should be selected and the first item in each list should have `tabindex="0"`
- When an item is focused, it becomes selected
- When focus leaves the list, the last selected item remains selected and focusable. When focus returns to the list focus is placed on the last selected item.
- When moving items:
  - With the move button: the items are unselected and added to the target list. The focus should remain on the move button.
  - With a keyboard shortcut: focus remains on the item, but in the target list. Since the item is focused, it is also selected.
  - If there are already selected items in the target list, they stay selected and the new items are added below them.

#### Keyboard Interactions

- Each list has a single focusable option inside. There is only ever one focusable option per list and it is expected that a user will use their arrow keys, and some modifier keys, to perform all actions.
- Because we support drag and drop re-ordering within a list, we implement the second multi-select keyboard model.
  - `up` and `down` arrows move focus _and_ selection, with `aria-selected="true"`. Any previously selected items are deselected.
  - `shift + up` and `shift + down` move focus and creates addition selections
  - `ctrl + down` or `ctrl + up` moves focus but selection remains where it is
  - `ctrl + space` toggles selection on the focused option, in addition to previous selections
  - `ctrl + a` selects all options in the list
  - `cmd/ctrl + right` and `cmd/ctrl + left` Moves selected items between lists
  - `space` toggles "Drag and Drop" mode. When in "Drag and Drop" mode:
    - `up` and `down` arrows move the selected items _within_ the current list

## Base

<Example title="Dueling Picklist with Reorder">
  <MultiSelect dataSet={DefaultSnapShot} />
</Example>

## Group Label

A Dueling Picklist should have a group label, similar to using a `fieldset` and `legend` on grouped form controls. To achieve this, wrap the Dueling Picklist in an `slds-form-element` and add a `div` with the same class names that are applied to a `legend` element in a fieldset, `slds-form-element__label slds-form-element__legend`.

<Blockquote header="Labeling the group" type="a11y">
  <p>
    It is important that the <code>slds-form-element</code> <code>&lt;div&gt;</code> has the <code>role="group"</code> attribute applied, along with <code>aria-labelledby</code>, whose value is
    the ID of the visible group label.
  </p>
</Blockquote>

<Example title="Dueling Picklist With Group Label">
  <CodeView>
    <MultiSelect dataSet={DefaultSnapShot} />
  </CodeView>
</Example>

## Responsive

To make the dueling picklist responsive or use it within narrow regions, apply the class `slds-dueling-picklist__column_responsive` to the `<div>`s with class `slds-dueling-picklist__column` that contain options (not the columns that only contain buttons). The dueling picklist will take up all available horizontal space, and any items longer than the available space will truncate with an ellipsis.

<Example title="Dueling Picklist Responsive">
  <CodeView>
    <MultiSelect dataSet={CountriesSnapshot} noReorder isResponsive />
  </CodeView>
</Example>

<Blockquote header="Adjusting Height" type="note">
  <p>
    To adjust the height of the listboxes, set the height using an inline style on
    _both_ of the <code>&lt;div&gt;</code>s with class <code>slds-dueling-picklist__column</code>. If
    you are setting it based on a maximum number of items being shown before
    scrolling, you can set <code>height = (2.25rem * numItems) + 1rem</code>.
  </p>
</Blockquote>

<CodeBlock toggleCode={false}>
  <div className="slds-dueling-list">
    <div className="slds-dueling-list__column">
      <span className="slds-form-element__label" id="label-1">
        Available Languages
      </span>
      <div className="slds-dueling-list__options" style={{ height: '10rem' }}>
        ...
      </div>
    </div>
    <div className="slds-dueling-list__column">...</div>
    <div className="slds-dueling-list__column">
      <span className="slds-form-element__label" id="label-2">
        Selected Languages
      </span>
      <div className="slds-dueling-list__options" style={{ height: '10rem' }}>
        ...
      </div>
    </div>
  </div>
</CodeBlock>

## Edit Mode

If the user needs to select multiple options for a field, like a list of languages supported, then use a dueling picklist without the re-order arrows on the right.

<Blockquote header="Helpful Assistive Text" type="a11y">
  <p>
    The assistive text content in the <code>option-drag-label</code> <code>&lt;div&gt;</code> should
    provide clear instructions on how to drag and drop with a keyboard. See the <a href="#Keyboard-Interactions">keyboard interactions section</a> above for modifier key information.
  </p>
</Blockquote>

<Example title="Dueling Picklist">
  <CodeView>
    <MultiSelect dataSet={CountriesSnapshot} noReorder />
  </CodeView>
</Example>

### Selected Item

<Blockquote header="Aria Selected" type="a11y">
  <p>
    <code>aria-selected</code> should be placed on each{' '}
    <code>role="option"</code>, and set to{' '}
    <code>true</code> when the item is selected.
  </p>
</Blockquote>

<Example title="Dueling Picklist with Item Selected">
  <CodeView>
    <MultiSelect dataSet={SelectedCountriesSnapshot} noReorder />
  </CodeView>
</Example>

### Multiple Selected Items

<Example title="Dueling Picklist with Multiple Items Selected">
  <CodeView>
    <MultiSelect dataSet={MultipleSelectedCountriesSnapshot} noReorder />
  </CodeView>
</Example>

### Dropped Items

<Blockquote type="a11y" header="Aria Live">
  <p>
    The <code>drag-live-region</code> <code>&lt;div&gt;</code> with <code>aria-live="assertive"</code> should
    update as items are moved to provide context about the state and location of
    the items.
  </p>
</Blockquote>

<CodeBlock toggleCode={false}>
  <div className="slds-dueling-list">
    <div
      className="slds-assistive-text"
      id="drag-live-region"
      aria-live="assertive"
    >
      Arabic and German: Moved to Selected Languages.
    </div>
  </div>
</CodeBlock>

<Example title="Dueling Picklist with Items Dropped">
  <CodeView>
    <MultiSelect dataSet={DroppedCountriesSnapshot} noReorder />
  </CodeView>
</Example>

### Locked Items

If items are not able to be removed or reordered from the selected list, a lock icon appears next to the item name.

<Blockquote type="a11y" header="Aria Disabled and Assistive Text">
  <p>
    For each locked item, <code>aria-disabled="true"</code> must
    be applied to <code>.slds-listbox__option</code> and assistive
    text (<code>.slds-assistive-text</code>) must be added to{' '}
    <code>.slds-icon_container</code>.
  </p>
</Blockquote>

<Example title="Dueling Picklist with a Locked Item">
  <CodeView>
    <MultiSelect dataSet={LockedSnapShot} noReorder />
  </CodeView>
</Example>

### With Reordering

If the order of the selected options matters, include the vertical arrows to the right. This allows the user to reorder the second listbox of options.

<Example title="Dueling Picklist with Reorder Active">
  <CodeView>
    <MultiSelect dataSet={DefaultSnapShot} />
  </CodeView>
</Example>

The following examples show the process of selecting an item, moving it within a list, and dropping it in a final position.

<Blockquote type="a11y" header="Aria Live">
  <p>
    Pay attention to the <code>drag-live-region</code> <code>&lt;div&gt;</code> with
    {' '}<code>aria-live="assertive"</code>. This should update as items are moved to provide
    context about the state and location of the items at all times.
  </p>
</Blockquote>

#### Item Selected

<Example title="Dueling Picklist with Reorder Active Item Selected">
  <CodeView>
    <MultiSelect dataSet={SelectedSnapShot} />
  </CodeView>
</Example>

#### Item Grabbed

Within a list, users are able to drag and drop an item.

<Example title="Dueling Picklist with Reorder Active Item Grabbed">
  <CodeView>
    <MultiSelect dataSet={GrabbedSnapShot} />
  </CodeView>
</Example>

#### Item Moved Within a List

<Example title="Dueling Picklist with Reorder Active Item Moved within List">
  <CodeView>
    <MultiSelect dataSet={MovedInSnapShot} />
  </CodeView>
</Example>

#### Item Dropped in a List

<Example title="Dueling Picklist with Reorder Active Item Dropped">
  <CodeView>
    <MultiSelect dataSet={DroppedSnapShot} />
  </CodeView>
</Example>

### Disabled

If the user is not able to interact with the dueling picklist, then it should be marked as disabled.

<Blockquote type="a11y" header="Aria Disabled">
  <p>
    In disabled mode, both list boxes{' '}
    <code>ul[role=listbox]</code> should receive{' '}
    <code>aria-disabled="true"</code>, and all directional buttons
    should receive the <code>disabled</code> attribute.
  </p>
</Blockquote>

<Blockquote type="note" header="Utility Class">
  <p>
    The class <code>slds-is-disabled</code> should also be applied
    to the divs with the class{' '}
    <code>slds-dueling-list_options</code>.
  </p>
</Blockquote>

<Example title="Dueling Picklist Disabled">
  <CodeView>
    <MultiSelect dataSet={DisabledSnapShot} disabled />
  </CodeView>
</Example>

### Required

<Example title="Dueling Picklist with Required Indicator">
  <CodeView>
    <MultiSelect dataSet={DefaultSnapShot} isRequired />
  </CodeView>
</Example>

### With Tooltip

If some contextual information regarding the dueling picklist is needed, add a tooltip next to the group label.

<Example title="Dueling Picklist with Tooltip">
  <CodeView>
    <Demo>
      <MultiSelect dataSet={DefaultSnapShot} hasTooltip showTooltip />
    </Demo>
  </CodeView>
</Example>

### Required With Tooltip

<Example title="Dueling Picklist with Required Indicator and Tooltip">
  <CodeView>
    <Demo>
      <MultiSelect
        dataSet={DefaultSnapShot}
        isRequired
        hasTooltip
        showTooltip
      />
    </Demo>
  </CodeView>
</Example>

## View Mode

When the user is done selecting options, or is in view mode of the field, they are presented with a comma separated list.

<Example title="Dueling Picklist in View Mode">
  <CodeView>
    <MultiSelectViewMode />
  </CodeView>
</Example>
